-- ======================================================================
-- Hell Lua Bus
-- 
-- Copyright 2012-2013Hell-Prototypes
--
-- http://www.hellprototypes.com/
--
-- This is free software, licensed under the terms of the GNU General
-- Public License as published by the Free Software Foundation.
-- ======================================================================
usb =require('libhlb')

module(..., package.seeall);

-- I2C pin index define --------------------------------------------------------
I2C_SCK_PIN		= 7
I2C_SDA_PIN		= 5

-- I2C device address define ---------------------------------------------------
IIC_WR_ADDR = 0xA0
IIC_RD_ADDR = 0xA1

-- -----------------------------------------------------------------------------
iic_byte_mask = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}
--iic_byte_mask = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}
function I2C_SCK_OUT()
	local ret = hlb.bit_oe(I2C_SCK_PIN, 1)
	if ret < 0 then
		print("I2C_SCK_OUT : hlb_bit_oe ret = ", ret)
	end
end
function I2C_SDA_IN()
	local ret = hlb.bit_oe(I2C_SDA_PIN, 0)
	if ret < 0 then
		print("I2C_SDA_IN : hlb_bit_oe ret = ", ret)
	end
end
function I2C_SDA_OUT()
	local ret = hlb.bit_oe(I2C_SDA_PIN, 1)
	if ret < 0 then
		print("I2C_SCK_OUT : hlb_bit_oe ret = ", ret)
	end
end
function I2C_GET_SDA()
	return hlb.get_bit(I2C_SDA_PIN)
end
function I2C_SDA_SET()
	local ret = hlb.set_bit(I2C_SDA_PIN)
	if ret < 0 then
		print("I2C_SDA_SET : usbhlb_set_bit ret = ", ret)
	end
end
function I2C_SDA_RESET()
	local ret = hlb.clr_bit(I2C_SDA_PIN)
	if ret < 0 then
		print("I2C_SDA_RESET : usbhlb_clr_bit ret = ", ret)
	end
end
function I2C_SCK_SET()
	local ret = hlb.set_bit(I2C_SCK_PIN)
	if ret < 0 then
		print("I2C_SCK_SET : usbhlb_set_bit ret = ", ret)
	end
end
function  I2C_SCK_RESET()
	local ret = hlb.clr_bit(I2C_SCK_PIN)
	if ret < 0 then
		print("I2C_SDA_RESET : usbhlb_clr_bit ret = ", ret)
	end
end
function WAIT_ETU()
	--hlb.usdelay(1)
	--hlb.msdelay(500)
end
-- -----------------------------------------------------------------------------
function io_init()
	I2C_SCK_SET()
	I2C_SCK_OUT()

	I2C_SDA_SET()
	I2C_SDA_OUT()
end

function device_addr(addr)
	IIC_WR_ADDR = addr
	IIC_RD_ADDR = addr + 1
end

function start()
	I2C_SDA_RESET()
	WAIT_ETU()
	I2C_SCK_RESET()
end

function wr_byte(ch)
	for index=1, 8 do
		mask = iic_byte_mask[9 - index]
		if bit32.btest(ch , mask) then
			I2C_SDA_SET()
		else 
			I2C_SDA_RESET()
		end

		WAIT_ETU()
		I2C_SCK_SET()
		WAIT_ETU()
		I2C_SCK_RESET()
	end

	I2C_SDA_IN()
	I2C_SDA_SET()
end

--true: no ack
--false: have ack
function rd_ack()
	local ret

	WAIT_ETU();
	I2C_SCK_SET();
	WAIT_ETU();

	if I2C_GET_SDA() then
		print("NAK")
		ret = true;
	else
		ret = false;
	end
	I2C_SCK_RESET()

	I2C_SDA_OUT()

	return ret;
end

function rd_byte_nak()
	local rd_data = 0
	
	I2C_SDA_IN()
	I2C_SDA_SET()
	for index=1, 8 do
		WAIT_ETU()
		I2C_SCK_SET()
		WAIT_ETU()
		if I2C_GET_SDA() then
			rd_data = rd_data + iic_byte_mask[9 - index]
		end
		I2C_SCK_RESET()

		WAIT_ETU()
	end
	
	I2C_SDA_SET()
	I2C_SDA_OUT()
	I2C_SCK_SET()
	WAIT_ETU()
	I2C_SCK_RESET()
	I2C_SDA_RESET()

	return rd_data
end

function rd_byte_ack()
	local rd_data = 0
	
	I2C_SDA_IN()
	I2C_SDA_SET()
	for index=1, 8 do
		WAIT_ETU()
		I2C_SCK_SET()
		WAIT_ETU()
		if I2C_GET_SDA() then
			rd_data = rd_data + iic_byte_mask[9 - index]
		end
		I2C_SCK_RESET()

		WAIT_ETU()
	end
	I2C_SDA_RESET()
	I2C_SDA_OUT()
	I2C_SCK_SET()
	WAIT_ETU()
	I2C_SCK_RESET()

	return rd_data
end

function stop()
	I2C_SDA_RESET()
	WAIT_ETU()
	I2C_SCK_SET()

	WAIT_ETU()
	I2C_SDA_SET()
end

function repeated_start()
	WAIT_ETU()
	I2C_SDA_SET()
	I2C_SDA_OUT()
	WAIT_ETU()
	I2C_SCK_SET()
	WAIT_ETU()
	I2C_SDA_RESET()
	WAIT_ETU()
	I2C_SCK_RESET()
	WAIT_ETU()
end
-- -----------------------------------------------------------------------------
function write_reg(reg_addr, data)
	start()

	wr_byte(IIC_WR_ADDR)
	if rd_ack() then
		stop()
		return false
	end

	wr_byte(reg_addr)
	if rd_ack() then
		stop()
		return false
	end
	
	wr_byte(data)
	if rd_ack() then
		stop()
		return false
	end
	
	stop()
	return true
end

function write_word_addr_reg(reg_addr, data)
	start()

	wr_byte(IIC_WR_ADDR)
	if rd_ack() then
		stop()
		return false
	end
	local H_Byte
	H_Byte = math.floor(reg_addr/256)
	-- print("H = " .. H_Byte .. ", L = " .. reg_addr - H_Byte*256 .. ", data = ", data)
	wr_byte(H_Byte)
	if rd_ack() then
		stop()
		return false
	end
	
	wr_byte(reg_addr - H_Byte*256)
	if rd_ack() then
		stop()
		return false
	end
	
	wr_byte(data)
	if rd_ack() then
		stop()
		return false
	end
	
	stop()
	hlb.msdelay(10)
	return true
end

function read_reg(reg_addr)
	local ret = 0

	start()

	wr_byte(IIC_WR_ADDR)
	if rd_ack() then
		stop()
		return ret
	end

	wr_byte(reg_addr)
	if rd_ack() then
		stop()
		return ret
	end

	repeated_start()

	wr_byte(IIC_RD_ADDR)
	if rd_ack() then
		stop()
		return ret
	end

	ret = rd_byte_nak()

	stop()

	return ret
end
function read_regs(start_reg_addr, reg_num)
	local ret_table = {}
	local ret = 0

	if reg_num < 1 then
		return ret_table
	end
	start()

	wr_byte(IIC_WR_ADDR)
	if rd_ack() then
		stop()
		return ret_table
	end

	wr_byte(start_reg_addr)
	if rd_ack() then
		stop()
		return ret_table
	end

	repeated_start()

	wr_byte(IIC_RD_ADDR)
	if rd_ack() then
		stop()
		return ret_table
	end
	for i=1, reg_num do
		if i < reg_num then
			ret_table[i]  = rd_byte_ack()
		else
			ret_table[i]  = rd_byte_nak()
		end
	end

	stop()

	return ret_table
end
function read_word_addr_regs(start_reg_addr, reg_num)
	local ret_table = {}
	local ret = 0

	if reg_num < 1 then
		return ret_table
	end
	start()

	wr_byte(IIC_WR_ADDR)
	if rd_ack() then
		stop()
		return ret_table
	end

	local H_Byte
	H_Byte = math.floor(start_reg_addr/256)
	wr_byte(H_Byte)
	if rd_ack() then
		stop()
		return ret_table
	end

	wr_byte(start_reg_addr - H_Byte*256)
	if rd_ack() then
		stop()
		return false
	end

	repeated_start()

	wr_byte(IIC_RD_ADDR)
	if rd_ack() then
		stop()
		return ret_table
	end
	for i=1, reg_num do
		if i < reg_num then
			ret_table[i]  = rd_byte_ack()
		else
			ret_table[i]  = rd_byte_nak()
		end
	end

	stop()

	return ret_table
end
-- -----------------------------------------------------------------------------
function device_open()
	local ret = hlb.usb_open()
	if ret < 0 then
		return false
	end
	
	return true
end

function device_close()
	local ret = hlb.usb_close()
	if ret < 0 then
		return false
	end
	
	return true
end